class DeepProxySandbox {
  constructor(name) {
    this.name = name; // 沙箱实例名称（方便调试）
    this.running = false; // 标记沙箱是否处于激活状态

    // 记录在沙箱中新增的属性（真实 window 上原本不存在的）
    this.addedPropsMap = new Map();

    // 记录在沙箱中被修改过的属性的原始值（方便停用时还原）
    this.modifiedPropsOriginalValueMap = new Map();

    // 记录当前沙箱中保存的属性值（顶层属性的最新值）
    this.currentUpdatedPropsValueMap = new Map();

    const rawWindow = window; // 保存真实的 window 引用

    // 缓存已经被代理过的对象，防止重复代理导致性能浪费
    const proxyCache = new WeakMap();

    /**
     * deepProxy 用于“深代理”
     * 也就是说不仅仅代理 fakeWindow 的顶层属性，
     * 如果属性值是对象（比如 document、location），也会给它加一层 Proxy
     */
    const deepProxy = (target) => {
      // 如果该对象已经被代理过，直接返回缓存
      if (proxyCache.has(target)) return proxyCache.get(target);

      // 创建对 target 的代理
      const p = new Proxy(target, {
        get: (obj, prop) => {
          const value = obj[prop];
          // 如果取到的值还是对象（非 null），递归进行深代理
          if (typeof value === 'object' && value !== null) {
            return deepProxy(value);
          }
          // 如果取到的是函数（且可绑定），绑定到原始对象，避免 this 丢失
          if (typeof value === 'function' && value.bind) {
            return value.bind(obj);
          }
          // 否则直接返回值
          return value;
        },
        set: (obj, prop, value) => {
          // 只有在沙箱运行状态下才允许修改
          if (this.running) {
            obj[prop] = value; // 直接修改对象属性
          }
          return true; // 返回 true 表示设置成功
        }
      });

      // 将代理对象缓存起来，下次用到同一个 target 时直接复用
      proxyCache.set(target, p);
      return p;
    };

    /**
     * 这是 fakeWindow 的顶层 Proxy
     * 用来拦截对 fakeWindow.xxx 的读写操作
     */
    this.proxy = new Proxy({}, {
      get: (target, prop) => {
        // 如果沙箱记录了该属性的最新值，优先返回它
        if (this.currentUpdatedPropsValueMap.has(prop)) {
          return this.currentUpdatedPropsValueMap.get(prop);
        }

        // 否则从真实 window 上取值
        const value = rawWindow[prop];

        // 如果取到的是对象，递归进行深代理（确保 document、location 等内部属性也能被代理）
        if (typeof value === 'object' && value !== null) {
          return deepProxy(value);
        }

        // 如果是函数（且可绑定），绑定到真实 window，避免 this 丢失
        if (typeof value === 'function' && value.bind) {
          return value.bind(rawWindow);
        }

        // 普通值直接返回
        return value;
      },
      set: (target, prop, value) => {
        if (this.running) {
          // 如果真实 window 上没有这个属性，说明是新增的
          if (!rawWindow.hasOwnProperty(prop)) {
            this.addedPropsMap.set(prop, value);
          }
          // 如果真实 window 上有这个属性，但我们没记录过原值，则保存原值
          else if (!this.modifiedPropsOriginalValueMap.has(prop)) {
            this.modifiedPropsOriginalValueMap.set(prop, rawWindow[prop]);
          }
          // 更新沙箱中该属性的当前值
          this.currentUpdatedPropsValueMap.set(prop, value);
        }
        return true; // 返回 true 表示设置成功
      }
    });
  }

  /** 激活沙箱（开启属性拦截） */
  active() {
    this.running = true;
  }

  /** 停用沙箱（恢复原始 window 状态） */
  inactive() {
    this.running = false;

    // 恢复所有被修改过的属性的原始值
    this.modifiedPropsOriginalValueMap.forEach((value, prop) => {
      window[prop] = value;
    });

    // 删除所有在沙箱中新增的属性
    this.addedPropsMap.forEach((_, prop) => {
      delete window[prop];
    });
  }
}


const sandbox = new DeepProxySandbox("AppA");

sandbox.active();

const fakeWindow = sandbox.proxy;

// 在沙箱内创建变量
fakeWindow.foo = "bar";
console.log(fakeWindow.foo); // bar
console.log(window.foo);     // undefined（不会污染真实 window）

// 修改 window 现有属性
fakeWindow.document.title = "Hello Sandbox";
console.log(document.title); // Hello Sandbox

sandbox.inactive();

// 再访问
console.log(window.foo); // undefined
console.log(document.title); // 原来的标题
